using System;
using System.Collections.Generic;

namespace Atomic.Libraries
{
	[Serializable]
	public class RollingCache<TKey, TValue>
	{
		private int capacity;
		[NonSerialized] private LinkedList<TKey> keys;
		[NonSerialized] private Dictionary<TKey, TValue> values;

		public RollingCache(int capacity)
		{
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException();
			}

			this.capacity = capacity;
		}
		
		public void Add(TKey key, TValue value)
		{
			if (capacity == 0)
			{
				// No caching; avoid locking.
				return;
			}

			if (keys == null || values == null)
			{
				keys = new LinkedList<TKey>();
				values = new Dictionary<TKey, TValue>(capacity);
			}

			if (values.ContainsKey(key))
			{
				// Put last in queue for removal.
				keys.Remove(key);
				keys.AddLast(key);

				// Overwrite if changed for some reason.
				values[key] = value;
			}
			else
			{
				if (keys.Count >= capacity)
				{
					values.Remove(keys.First.Value);
					keys.RemoveFirst();
				}

				values.Add(key, value);
				keys.AddLast(key);
			}
		}

		public bool TryGetValue(TKey key, out TValue value)
		{
			if (capacity == 0 || values == null)
			{
				value = default(TValue);
				return false;
			}

			return values.TryGetValue(key, out value);
		}
	}
}
